package wallet

import (
	"bytes"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"errors"
	"publicChainSystem/tools"
)

/**
 *@author:zhengyilong
 *@email:1797344574@qq.com
 *@phone:13479394730
 *@DateTime:2022/5/23 9:15
 **/

//版本号
const VERSION = 0x00

//生成公钥和私钥
func NewPubKeys()(*ecdsa.PrivateKey,*ecdsa.PublicKey,error) {
	//生成一个p256的曲线
	curve := elliptic.P256()

	//创建私钥
	privateKey, err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil {
		return nil,nil,err
	}

	//生成公钥
	publicKey := privateKey.PublicKey
	return privateKey,&publicKey,nil
}

//生成比特币地址
func GenerateAddr()(string,error) {
	//获取公钥
	_, pub, err := NewPubKeys()
	if err != nil {
		return "",err
	}

	//对公钥进行类型转换，序列化
	pub_byte := elliptic.Marshal(pub.Curve, pub.X, pub.Y)

	//对公钥进行sha256计算
	pub_sha256 := tools.GetHash(pub_byte)

	//进行ripmed160计算	20个字节，160位
	pubhash := tools.Ripemd160(pub_sha256)

	//将版本号和pubhash进行拼接
	ver_pubhash := append([]byte{VERSION}, pubhash...)

	//双重sha256
	first_hash := tools.GetHash(ver_pubhash)
	second_hash := tools.GetHash(first_hash)

	//取前四个字节为校验码
	check := second_hash[:4]

	//将check拼接到ver_pubhash后面
	ver_pubhash_check := append(ver_pubhash,check...)

	//对最后的结果进行base58编码
	address := tools.Encode(ver_pubhash_check)
	return address,nil
}

//对地址进行校验
func checkAddr(address string) bool {
	if len(address) != 34 {
		return false
	}
	//1、使用base58算法对给定的字符串进行解码操作，得到一个解码序列
	decodeAddress := tools.Decode(address)

	//2、在得到的解码序列中取后四个字节，命名为check
	check := decodeAddress[len(decodeAddress)-4:len(decodeAddress)]

	//3、取第二步中剩余的序列，进行双重hash计算，并得到校验码
	ver_pub := decodeAddress[0:len(decodeAddress)-4]
	hash := tools.GetHash(ver_pub)
	hash2 := tools.GetHash(hash)
	verify_check := hash2[:4]

	//4、将第二步中的check与第四步中的verify_check进行比较，判断
	isValid := bytes.Compare(check, verify_check)
	return isValid == 0
}

//根据地址获取公钥hash
func GetPubHash(address string) ([]byte,error) {
	//判断传入的是否为比特币地址
	istrue := checkAddr(address)
	if !istrue {
		return nil,errors.New("地址不合法")
	}

	//解码
	ver_pubhash_check := tools.Decode(address)

	//截取掉check，得到ver_pubhash
	ver_pubhash := ver_pubhash_check[:len(ver_pubhash_check)-4]

	//截取掉ver，得到pubhash
	pubhash := ver_pubhash[1:]

	return pubhash,nil
}